﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace GameEngine.MoveGenerators
{
    /// <summary>
    /// Parent root for all move generators. Contains basic methods for investigating moves
    /// </summary>
    public class BaseMoveGenerator
    {
        /// <summary>
        /// Relationship to gameboard. Set up GameRuleControllerBuilder
        /// </summary>
        public GameBoard GameBoard
        { get; set; }

        /// <summary>
        /// Detects whether figure given by position of on move
        /// </summary>
        protected bool IsFigureOnMove(Position pos)
        {
            enumFigureType ft = GameBoard.GetField(pos.Row, pos.Col);
            if (ft == enumFigureType.Nothing)
                return false;
            return ft.FigureColor() == GameBoard.OnMove ? true : false;
        }

        /// <summary>
        /// Checkes whether is it the place where a figure can move
        /// </summary>
        protected bool IsPlaceFreeToMove(Position pos)
        {
            if (GameBoard.IsOutsideBoard(pos) == true)
                return false;
            return GameBoard.GetField(pos.Row, pos.Col) == enumFigureType.Nothing ? true : false;
        }

        /// <summary>
        /// For international checkers we have to check, whether the move from promotion row
        /// does not continue with jump, if yes, we cannot convert to king
        /// CHANGES FOR RUSSIAN CHECKERS
        /// </summary>
        protected virtual bool DoesMoveContinueWithJump(Position figurePos, enumManOrientation eOrientation)
        {
            return false;
        }

        /// <summary>
        /// Checks whether we should convert to King. 
        /// </summary>
        protected virtual bool ShouldConvertToKing(Position pos, enumManOrientation eOrientation, bool bJump)
        {
            enumFigureType figure = GameBoard.GetField(pos);
            if (figure == enumFigureType.Nothing)
                return false;
            if (figure.IsKing() == true)
                return false;

            // check additional jumps only when the last move is jump
            if (bJump == true)
            {
                // Checks whether the move from promotion row does not continue with jump,
                // if yes, we cannot promote to the king
                if (DoesMoveContinueWithJump(pos, eOrientation) == true)
                    return false;
            }
            
            if ((pos.Row == 0 && eOrientation == enumManOrientation.Down)
                || (pos.Row == GameBoard.Size - 1 && eOrientation == enumManOrientation.Up))
            {
                return true;
            } // if

            return false;
        }

        /// <summary>
        /// Fill in the move the jumped figure
        /// </summary>
        private void GetJumpedFigure(Move move, Position start, Position end)
        {
            move.RemovingFigure = true;
            enumDiagonalDir dir = end.GetDiagonalDir(start);
            Position pos = end;
            do
            {
                pos = pos.GetNextField(dir);
            } while (GameBoard.IsOutsideBoard(pos) == true || GameBoard.GetField(pos) == enumFigureType.Nothing);

            move.removedFigurePlace = pos;
            move.removedFigure = GameBoard.GetField(move.removedFigurePlace);


            Debug.Assert(GameBoard.IsOutsideBoard(move.removedFigurePlace) == false);
            Debug.Assert(move.removedFigure != enumFigureType.Nothing);
        }


        /// <summary>
        /// Checks whether this move to do is jump
        /// </summary>
        /// <param name="move">The move currently to do<param>
        /// <returns></returns>
        private bool IsMoveToDoJump(Move move)
        {
            enumDiagonalDir dir = move.endPos.GetDiagonalDir(move.startPos);
            Position pos = move.endPos;
            do
            {
                // get field
                enumFigureType figureType = GameBoard.GetField(pos);
                if (figureType != enumFigureType.Nothing)
                {
                    if (figureType.FigureColor() != GameBoard.GetField(move.startPos).FigureColor())
                        return true;
                    else
                        return false;
                }

                pos = pos.GetNextField(dir);
            } while (pos != move.startPos);

            return false;
        }

        /// <summary>
        /// Completes one move step
        /// </summary>
        public Move CompleteMoveStep(Position start, Position end, enumManOrientation eOrientation)
        {
            Move move = new Move();
            move.bitOriginalPosition = GameBoard.PackGameBoard();
            move.startPos = start;
            move.endPos = end;

            // check the jump
            if (IsMoveToDoJump(move))
            {
                GetJumpedFigure(move, start, end);
            }
            else
            {
                // fill in empty jump
                move.RemovingFigure = false;
                move.removedFigure = enumFigureType.Nothing;
                move.removedFigurePlace = new Position();
            }
           
            // check conversion to King
            GameBoard.DoMove(move);
            move.convertedToKing = ShouldConvertToKing(move.endPos, eOrientation, move.RemovingFigure == true);
            GameBoard.UndoMove(move);
            
            move.nextMove = null; // this is just for one move step
            return move;
        }

    }
}
